import { Injectable } from '@nestjs/common';
import * as os from 'os';
import { DataSource } from 'typeorm';
import * as fs from 'fs';
import * as path from 'path';
import * as crypto from 'crypto';
import * as packageJson from '../../package.json';

@Injectable()
export class InstallService {
  checkEnvironment() {
    return {
      adminVersion: (packageJson as { version: string }).version,
      nodeVersion: process.version,
      serverOS: os.platform(),
      databaseConfig: {
        type: process.env.DB_TYPE as 'mysql',
        host: process.env.DB_HOST,
        port: parseInt(process.env.DB_PORT as string, 10) || 3306,
        username: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_DATABASE,
        charset: process.env.DB_CHARSET,
        prefix: process.env.DB_PREFIX,
      },
    };
  }

  createPassword(pwd: string, salt: string): string {
    // 内部MD5计算：md5(pwd + salt)
    const innerHash = crypto
      .createHash('md5')
      .update(pwd + salt)
      .digest('hex');
    // 最终MD5计算：md5(salt + innerHash)
    const finalHash = crypto
      .createHash('md5')
      .update(salt + innerHash)
      .digest('hex');
    return finalHash;
  }

  initAccount(admin: { username: string; password: string }): string[] {
    const time = Math.floor(Date.now() / 1000); // 等同于PHP的time()

    // 相同的盐值生成逻辑
    const salt = crypto
      .createHash('md5')
      .update(time.toString() + admin.username)
      .digest('hex')
      .substring(0, 4); // 随机4位密码盐

    // 相同的密码创建逻辑
    const password = this.createPassword(admin.password, salt);

    // 完全相同的SQL语句构建
    const sql = [
      `INSERT INTO \`la_admin\`(\`id\`, \`root\`, \`name\`, \`avatar\`, \`account\`, \`password\`, \`login_time\`, \`login_ip\`, \`multipoint_login\`, \`disable\`, \`create_time\`, \`update_time\`, \`delete_time\`) ` +
        `VALUES (1, 1, '${admin.username}', '', '${admin.password}', '${password}', '${time}', '', 1, 0, '${time}', '${time}', NULL);`,
      // 相同的管理员关联部门SQL
      `INSERT INTO \`la_admin_dept\` (\`admin_id\`, \`dept_id\`) VALUES (1, 1);`,
    ];
    return sql;
  }

  async createTable(admin: { username: string; password: string }) {
    const dbFile = path.join(
      __dirname,
      '../../public/install-page/db/like.sql',
    );
    let content = fs.readFileSync(dbFile, 'utf-8');
    content = content.replace(/;\r\n/g, ';\n');
    const tables = content.split(';\n');
    tables.push(...this.initAccount(admin));

    const connection = new DataSource({
      type: 'mysql',
      host: process.env.DB_HOST || 'localhost',
      port: parseInt(process.env.DB_PORT || '3306', 10),
      username: process.env.DB_USERNAME || '',
      password: process.env.DB_PASSWORD || '',
      database: process.env.DB_DATABASE || '',
      charset: process.env.DB_CHARSET || 'utf8mb4',
    });

    try {
      // 先建立连接
      await connection.initialize();

      // 获取mysql版本
      const versionResult = (await connection.query(
        'SELECT version() as version',
      )) as unknown as { version: string }[];
      const version = parseFloat(versionResult[0].version);

      for (const table of tables) {
        const trimmedTable = table.trim();
        if (!trimmedTable) continue;
        if (trimmedTable.indexOf('--') === 0) continue;

        let processedTable = trimmedTable
          .replace(/`la_/g, `${process.env.DB_DATABASE ?? ''}.\`la_`)
          .replace(/`la_/g, `\`${process.env.DB_PREFIX ?? ''}`);

        if (trimmedTable.includes('CREATE') && version <= 4.1) {
          processedTable = processedTable.replace('DEFAULT CHARSET=utf8', '');
        }

        try {
          await connection.query(processedTable);
        } catch (e) {
          console.error('Error executing SQL:', processedTable);
          console.error(e);
          return false;
        }
      }
      return true;
    } finally {
      if (connection.isInitialized) {
        await connection.destroy();
      }
    }
  }
}
